package com.huilian.iotbox.data.utils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat;

/**
 * 娃娃机（九酷专版）单独用到的
 *
 * @author chenqiwen
 * @CreateDate: 2021-04-13-20-18
 * @Description:
 */
public class CRC16MODBUSUtil {

    public static int decimalConvertHexLength_2 = 2;
    public static int decimalConvertHexLength_4 = 4;

    /**
     * 接收到的字节数组转换16进制字符串
     */
    public static String byteToStr(byte[] b, int size) {
        String ret = "";
        for (int i = 0; i < size; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            ret += hex.toUpperCase();
        }
        return ret;
    }

    /**
     * 将16进制字符串转换为byte[]
     *
     * @param str
     * @return
     */
    public static byte[] toBytes(String str) {
        byte[] bytes = new BigInteger(str, 16).toByteArray();
        return bytes;
    }

    /**
     * 计算CRC16/Modbus校验码  低位在前,高位在后
     *
     * @param str 十六进制字符串
     * @return
     */
    public static String getCRC(String str) {
        byte[] bytes = toBytes(str);
        int CRC = 0x0000ffff;
        int POLYNOMIAL = 0x0000a001;

        int i, j;
        for (i = 0; i < bytes.length; i++) {
            CRC ^= ((int) bytes[i] & 0x000000ff);
            for (j = 0; j < 8; j++) {
                if ((CRC & 0x00000001) != 0) {
                    CRC >>= 1;
                    CRC ^= POLYNOMIAL;
                } else {
                    CRC >>= 1;
                }
            }
        }
        String crc = Integer.toHexString(CRC);
        if (crc.length() == 2) {
            crc = "00" + crc;
        } else if (crc.length() == 3) {
            crc = "0" + crc;
        }
        crc = crc.substring(2, 4) + crc.substring(0, 2);
        return crc.toUpperCase();
    }


    /**
     * 十六进制字符串高低位转换，高字节在前 低字节在后
     * 适合于1字节生成2个字节,2字节生成2个字节
     * 比喻10进制转16进制，1转01，然后高在前，低在后，生成0100
     *
     * @return
     */
    public static String reverseHex(String hex) {
        char[] charArray = hex.toCharArray();
        int length = charArray.length;
        int times = length / 2;
        for (int c1i = 0; c1i < times; c1i += 2) {
            int c2i = c1i + 1;
            char c1 = charArray[c1i];
            char c2 = charArray[c2i];
            int c3i = length - c1i - 2;
            int c4i = length - c1i - 1;
            charArray[c1i] = charArray[c3i];
            charArray[c2i] = charArray[c4i];
            charArray[c3i] = c1;
            charArray[c4i] = c2;
        }
        String s = new String(charArray);
        if (s.length() % 4 == 2) {
            s = s + "00";
        }
        return s;
    }

    /**
     * 注意：这是返回int型，可以是负数
     * 单个16进制转10进制
     *
     * @param hex
     * @return
     */
    public static int singleHexConvertDecimal(String hex) {
        if (hex.length() == 2) {
            // 一个字节时
            return new BigInteger(hex, 16).intValue();
        } else if (hex.length() == 4) {
            // 两个字节时，并且判断高低位转换

            // 高位
            String high = hex.substring(0, 2);
            // 低位
            String low = hex.substring(2, 4);
            if (new BigInteger(high, 16).intValue() > new BigInteger(low, 16).intValue()) {
                return new BigInteger(low + high, 16).intValue();
            }
            return new BigInteger(high + low, 16).intValue();
        }
        return 0;
    }

    /**
     * 注意：这里只生成int型，可以是负数
     * 单个10进制转16进制
     *
     * @param in：被转换的
     * @param length：取值2和4。转换之后的长度，如输入singleDecimalConvertHex(1, 2)
     * @return
     */
    public static String singleDecimalConvertHex(int in, int length) {
        /**
         * Integer.toHexString(in)
         * 如果输入负数就会报错，所以下面的路由解决
         */
        // %x就是格式化成十六进制(X就是大写，x就是小写)，8表示生成字符长度8位，0表示如果不够8位则往前面补0。
        String s = "%0" + length + "x";
        return String.format(s, in);
    }

    /**
     * 注意：这是返回BigDecimal型，带小数点
     * 单个16进制转10进制
     *
     * @param hex
     * @return
     */
    public static BigDecimal singleHexConvertBigDecimal(String hex) {
        if (hex.length() == 2) {
            // 一个字节时
            return BigDecimal.valueOf(new BigInteger(hex, 16).intValue() * 1.0 / 100);
//            return formatToNumber(BigDecimal.valueOf(new BigInteger(hex, 16).intValue() * 1.0 / 100));
        } else if (hex.length() == 4) {
            // 两个字节时，并且判断高低位转换

            // 高位
            String high = hex.substring(0, 2);
            // 低位
            String low = hex.substring(2, 4);
            if (new BigInteger(high, 16).intValue() > new BigInteger(low, 16).intValue()) {
                return BigDecimal.valueOf(new BigInteger(low + high, 16).intValue() * 1.0 / 100);
//                return formatToNumber(BigDecimal.valueOf(new BigInteger(low + high, 16).intValue() * 1.0 / 100));
            }
            return BigDecimal.valueOf(new BigInteger(high + low, 16).intValue() * 1.0 / 100);
//            return formatToNumber(BigDecimal.valueOf(new BigInteger(high + low, 16).intValue() * 1.0 / 100));
        }
        return BigDecimal.ZERO;
//        return formatToNumber(BigDecimal.ZERO);
    }

    /**
     * 注意：这里只生成BigDecimal型，因为有两位小数，一开始就要先乘以100，再转16进制
     * 单个10进制转16进制
     *
     * @param in：被转换的
     * @param length：取值2和4。转换之后的长度，singleBigDecimalConvertHex(1, 2)
     * @return
     */
    public static String singleBigDecimalConvertHex(BigDecimal in, int length) {
        StringBuffer sb = new StringBuffer();
        // 将小数点转向右移动两位，也就是乘以100
        String str = Integer.toHexString(in.multiply(new BigDecimal(100)).intValue());
        if (str.length() % 2 == 1) {
            for (int i = 1; i <= length - str.length(); i++) {
                sb.append("0");
            }
        }
        sb.append(str);
        return sb.toString();
    }


    /**
     * BigDecimal格式两位小数
     *
     * @param obj:传入的小数
     * @return
     * @desc 1.0~1之间的BigDecimal小数，格式化后失去前面的0,则前面直接加上0。
     * 2.传入的参数等于0，则直接返回字符串"0.00"
     * 3.大于1的小数，直接格式化返回字符串
     */
    public static String formatToNumber(BigDecimal obj) {
        DecimalFormat df = new DecimalFormat("#.00");
        if (obj.compareTo(BigDecimal.ZERO) == 0) {
            return "0.00";
        } else if (obj.compareTo(BigDecimal.ZERO) > 0 && obj.compareTo(new BigDecimal(1)) < 0) {
            return "0" + df.format(obj);
        } else if (obj.compareTo(BigDecimal.ZERO) < 0 && obj.compareTo(new BigDecimal(-1)) > 0) {
            df = new DecimalFormat("0.00");
            return df.format(obj);
        } else if (obj.compareTo(BigDecimal.ZERO) < 0 && obj.compareTo(new BigDecimal(-1)) > 0) {
            df = new DecimalFormat("0.00");
            return df.format(obj);
        } else {
            return df.format(obj);
        }
    }

}
